[Chapter Eleven][Previous]
[Art of Assembly][Randall
Hyde]
Art of Assembly: Chapter Eleven
- 11.10 - Sample Program
11.10 Sample Program
The following sample program demonstrates several concepts appearing
in this chapter, most notably, passing parameters on the stack. This program
(Pgm11_1.asm appearing on the companion CD-ROM) manipulates the PC's memory-mapped
text video display screen (at address B800:0 for color displays, B000:0
for monochrome displays). It provides routines that "capture"
all the data on the screen to an array, write the contents of an array to
the screen, clear the screen, scroll one line up or down, position the cursor
at an (X,Y) coordinate, and retrieve the current cursor position.
Note that this code was written to demonstrate the use of parameters and
local variables. Therefore, it is rather inefficient. As the comments point
out, many of the functions this package provides could be written to run
much faster using the 80x86 string instructions. See the laboratory exercises
for a different version of some of these functions that is written in such
a fashion. Also note that this code makes some calls to the PC's BIOS to
set and obtain the cursor position as well as clear the screen. See the
chapter on BIOS and DOS for more details on these BIOS calls.
; Pgm11_1.asm
;
; Screen Aids.
;
; This program provides some useful screen manipulation routines
; that let you do things like position the cursor, save and restore
; the contents of the display screen, clear the screen, etc.
;
; This program is not very efficient. It was written to demonstrate
; parameter passing, use of local variables, and direct conversion of
; loops to assembly language. There are far better ways of doing
; what this program does (running about 5-10x faster) using the 80x86
; string instructions.
.xlist
include stdlib.a
includelib stdlib.lib
.list
.386 ;Comment out these two statements
option segment:use16 ; if you are not using an 80386.
; ScrSeg- This is the video screen's segment address. It should be
; B000 for mono screens and B800 for color screens.
ScrSeg = 0B800h
dseg segment para public 'data'
XPosn word ? ;Cursor X-Coordinate (0..79)
YPosn word ? ;Cursor Y-Coordinate (0..24)
; The following array holds a copy of the initial screen data.
SaveScr word 25 dup (80 dup (?))
dseg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg
; Capture- Copies the data on the screen to the array passed
; by reference as a parameter.
;
; procedure Capture(var ScrCopy:array[0..24,0..79] of word);
; var x,y:integer;
; begin
;
; for y := 0 to 24 do
; for x := 0 to 79 do
; SCREEN[y,x] := ScrCopy[y,x];
; end;
;
;
; Activation record for Capture:
;
; | |
; | Previous stk contents |
; -------------------------
; | ScrCopy Seg Adrs |
; -- --
; | ScrCopy offset Adrs |
; -------------------------
; | Return Adrs (near) |
; -------------------------
; | Old BP |
; ------------------------- <- BP
; | X coordinate value |
; -------------------------
; | Y coordinate value |
; -------------------------
; | Registers, etc. |
; ------------------------- <- SP
ScrCopy_cap textequ <dword ptr [bp+4]>
X_cap textequ <word ptr [bp-2]>
Y_cap textequ <word ptr [bp-4]>
Capture proc
push bp
mov bp, sp
sub sp, 4 ;Allocate room for locals.
push es
push ds
push ax
push bx
push di
mov bx, ScrSeg ;Set up pointer to SCREEN
mov es, bx ; memory (ScrSeg:0).
lds di, ScrCopy_cap ;Get ptr to capture array.
mov Y_cap, 0
YLoop: mov X_cap, 0
XLoop: mov bx, Y_cap
imul bx, 80 ;Screen memory is a 25x80 array
add bx, X_cap ; stored in row major order
add bx, bx ; with two bytes per element.
mov ax, es:[bx] ;Read character code from screen.
mov ds:[di][bx], ax ;Store away into capture array.
inc X_Cap ;Repeat for each character on this
cmp X_Cap, 80 ; row of characters (each character
jb XLoop ; in the row is two bytes).
inc Y_Cap ;Repeat for each row on the screen.
cmp Y_Cap, 25
jb YLoop
pop di
pop bx
pop ax
pop ds
pop es
mov sp, bp
pop bp
ret 4
Capture endp
; Fill- Copies array passed by reference onto the screen.
;
; procedure Fill(var ScrCopy:array[0..24,0..79] of word);
; var x,y:integer;
; begin
;
; for y := 0 to 24 do
; for x := 0 to 79 do
; ScrCopy[y,x] := SCREEN[y,x];
; end;
;
;
; Activation record for Fill:
;
; | |
; | Previous stk contents |
; -------------------------
; | ScrCopy Seg Adrs |
; -- --
; | ScrCopy offset Adrs |
; -------------------------
; | Return Adrs (near) |
; -------------------------
; | Old BP |
; ------------------------- <- BP
; | X coordinate value |
; -------------------------
; | Y coordinate value |
; -------------------------
; | Registers, etc. |
; ------------------------- <- SP
ScrCopy_fill textequ <dword ptr [bp+4]>
X_fill textequ <word ptr [bp-2]>
Y_fill textequ <word ptr [bp-4]>
Fill proc
push bp
mov bp, sp
sub sp, 4
push es
push ds
push ax
push bx
push di
mov bx, ScrSeg ;Set up pointer to SCREEN
mov es, bx ; memory (ScrSeg:0).
lds di, ScrCopy_fill ;Get ptr to data array.
mov Y_Fill, 0
YLoop: mov X_Fill, 0
XLoop: mov bx, Y_Fill
imul bx, 80 ;Screen memory is a 25x80 array
add bx, X_Fill ; stored in row major order
add bx, bx ; with two bytes per element.
mov ax, ds:[di][bx] ;Store away into capture array.
mov es:[bx], ax ;Read character code from screen.
inc X_Fill ;Repeat for each character on this
cmp X_Fill, 80 ; row of characters (each character
jb XLoop ; in the row is two bytes).
inc Y_Fill ;Repeat for each row on the screen.
cmp Y_Fill, 25
jb YLoop
pop di
pop bx
pop ax
pop ds
pop es
mov sp, bp
pop bp
ret 4
Fill endp
; Scroll_up- Scrolls the screen up on line. It does this by copying the second line
; to the first, the third line to the second, the fourth line to the third,
; etc.
;
; procedure Scroll_up;
; var x,y:integer;
; begin
; for y := 1 to 24 do
; for x := 0 to 79 do
; SCREEN[Y-1,X] := SCREEN[Y,X];
; end;
;
; Activation record for Scroll_up:
;
; | |
; | Previous stk contents |
; -------------------------
; | Return Adrs (near) |
; -------------------------
; | Old BP |
; ------------------------- <- BP
; | X coordinate value |
; -------------------------
; | Y coordinate value |
; -------------------------
; | Registers, etc. |
; ------------------------- <- SP
X_su textequ <word ptr [bp-2]>
Y_su textequ <word ptr [bp-4]>
Scroll_up proc
push bp
mov bp, sp
sub sp, 4 ;Make room for X, Y.
push ds
push ax
push bx
mov ax, ScrSeg
mov ds, ax
mov Y_su, 0
su_Loop1: mov X_su, 0
su_Loop2: mov bx, Y_su ;Compute index into screen
imul bx, 80 ; array.
add bx, X_su
add bx, bx ;Remember, this is a word array.
mov ax, ds:[bx+160] ;Fetch word from source line.
mov ds:[bx], ax ;Store into dest line.
inc X_su
cmp X_su, 80
jb su_Loop2
inc Y_su
cmp Y_su, 80
jb su_Loop1
pop bx
pop ax
pop ds
mov sp, bp
pop bp
ret
Scroll_up endp
; Scroll_dn- Scrolls the screen down one line. It does this by copying the 24th line
; to the 25th, the 23rd line to the 24th, the 22nd line to the 23rd,
; etc.
;
; procedure Scroll_dn;
; var x,y:integer;
; begin
; for y := 23 downto 0 do
; for x := 0 to 79 do
; SCREEN[Y+1,X] := SCREEN[Y,X];
; end;
;
; Activation record for Scroll_dn:
;
; | |
; | Previous stk contents |
; -------------------------
; | Return Adrs (near) |
; -------------------------
; | Old BP |
; ------------------------- <- BP
; | X coordinate value |
; -------------------------
; | Y coordinate value |
; -------------------------
; | Registers, etc. |
; ------------------------- <- SP
X_sd textequ <word ptr [bp-2]>
Y_sd textequ <word ptr [bp-4]>
Scroll_dn proc
push bp
mov bp, sp
sub sp, 4 ;Make room for X, Y.
push ds
push ax
push bx
mov ax, ScrSeg
mov ds, ax
mov Y_sd, 23
sd_Loop1: mov X_sd, 0
sd_Loop2: mov bx, Y_sd ;Compute index into screen
imul bx, 80 ; array.
add bx, X_sd
add bx, bx ;Remember, this is a word array.
mov ax, ds:[bx] ;Fetch word from source line.
mov ds:[bx+160], ax ;Store into dest line.
inc X_sd
cmp X_sd, 80
jb sd_Loop2
dec Y_sd
cmp Y_sd, 0
jge sd_Loop1
pop bx
pop ax
pop ds
mov sp, bp
pop bp
ret
Scroll_dn endp
; GotoXY- Positions the cursor at the specified X, Y coordinate.
;
; procedure gotoxy(x,y:integer);
; begin
; BIOS(posnCursor,x,y);
; end;
;
; Activation record for GotoXY
;
; | |
; | Previous stk contents |
; -------------------------
; | X coordinate value |
; -------------------------
; | Y coordinate value |
; -------------------------
; | Return Adrs (near) |
; -------------------------
; | Old BP |
; ------------------------- <- BP
; | Registers, etc. |
; ------------------------- <- SP
X_gxy textequ <byte ptr [bp+6]>
Y_gxy textequ <byte ptr [bp+4]>
GotoXY proc
push bp
mov bp, sp
push ax
push bx
push dx
mov ah, 2 ;Magic BIOS value for gotoxy.
mov bh, 0 ;Display page zero.
mov dh, Y_gxy ;Set up BIOS (X,Y) parameters.
mov dl, X_gxy
int 10h ;Make the BIOS call.
pop dx
pop bx
pop ax
mov sp, bp
pop bp
ret 4
GotoXY endp
; GetX- Returns cursor X-Coordinate in the AX register.
GetX proc
push bx
push cx
push dx
mov ah, 3 ;Read X, Y coordinates from
mov bh, 0 ; BIOS
int 10h
mov al, dl ;Return X coordinate in AX.
mov ah, 0
pop dx
pop cx
pop bx
ret
GetX endp
; GetY- Returns cursor Y-Coordinate in the AX register.
GetY proc
push bx
push cx
push dx
mov ah, 3
mov bh, 0
int 10h
mov al, dh ;Return Y Coordinate in AX.
mov ah, 0
pop dx
pop cx
pop bx
ret
GetY endp
; ClearScrn- Clears the screen and positions the cursor at (0,0).
;
; procedure ClearScrn;
; begin
; BIOS(Initialize)
; end;
ClearScrn proc
push ax
push bx
push cx
push dx
mov ah, 6 ;Magic BIOS number.
mov al, 0 ;Clear entire screen.
mov bh, 07 ;Clear with black spaces.
mov cx, 0000 ;Upper left corner is (0,0)
mov dl, 79 ;Lower X-coordinate
mov dh, 24 ;Lower Y-coordinate
int 10h ;Make the BIOS call.
push 0 ;Position the cursor to (0,0)
push 0 ; after the call.
call GotoXY
pop dx
pop cx
pop bx
pop ax
ret
ClearScrn endp
; A short main program to test out the above:
Main proc
mov ax, dseg
mov ds, ax
mov es, ax
meminit
; Save the screen as it looks when this program is run.
push seg SaveScr
push offset SaveScr
call Capture
call GetX
mov XPosn, ax
call GetY
mov YPosn, ax
; Clear the screen to prepare for our stuff.
call ClearScrn
; Position the cursor in the middle of the screen and print some stuff.
push 30 ;X value
push 10 ;Y value
call GotoXY
print
byte "Screen Manipulatation Demo",0
push 30
push 11
call GotoXY
print
byte "Press any key to continue",0
getc
; Scroll the screen up two lines
call Scroll_up
call Scroll_up
getc
;Scroll the screen down four lines:
call Scroll_dn
call Scroll_dn
call Scroll_dn
call Scroll_dn
getc
; Restore the screen to what it looked like prior to this call.
push seg SaveScr
push offset SaveScr
call Fill
push XPosn
push YPosn
call GotoXY
Quit: ExitPgm ;DOS macro to quit program.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
- 11.10 - Sample Program
Art of Assembly: Chapter Eleven - 27 SEP 1996
[Chapter Eleven][Previous]
[Next] [Art of Assembly][Randall
Hyde]